package tr.edu.ege.kipler.satisfiability.completion.rules.dl;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import tr.edu.ege.kipler.satisfiability.UnsatisfiableException;
import tr.edu.ege.kipler.satisfiability.container.ABox;
import tr.edu.ege.kipler.satisfiability.container.Individual;
import tr.edu.ege.kipler.satisfiability.container.SHIQABox;
import tr.edu.ege.kipler.satisfiability.container.WcsData;
import tr.edu.ege.kipler.satisfiability.container.WorldConstraintSystem;
import tr.edu.ege.kipler.syntax.Role;
import tr.edu.ege.kipler.syntax.atomicformula.SameIndividualAssertion;

/**
 * 
 * @author İnanç Seylan
 * 
 */
public class SHIQABoxBothRootMergeStrategy implements MergeStrategy {

	private SHIQABox aBox;

	private Set<WorldConstraintSystem> dependencySet = new HashSet<WorldConstraintSystem>();;

	private SHIQABox getABox() {
		return aBox;
	}

	private void setABox(ABox box) {
		aBox = (SHIQABox) box;
	}

	private Set<WorldConstraintSystem> getDependencySet() {
		return dependencySet;
	}

	private void setDependencySet(Set<WorldConstraintSystem> dependedWcs) {
		this.dependencySet = dependedWcs;
	}

	public MergePair choosePair(ABox aBox, Set<Individual> neighbors) {
		setABox(aBox);
		MergePair result = MergePair.emptyPair();
		Iterator<Individual> i = neighbors.iterator();
		while (i.hasNext() && result == null) {
			Individual indv1 = i.next();
			Iterator<Individual> j = neighbors.iterator();
			while (j.hasNext() && result == null) {
				Individual indv2 = j.next();
				SameIndividualAssertion ia = new SameIndividualAssertion(indv1
						.getName(), indv2.getName()).toggleNegated();
				if (!indv1.equals(indv2) && !getABox().contains(ia)
						&& getABox().isRoot(indv1) && getABox().isRoot(indv2)) {
					result = new MergePair(indv2.getName(), indv1.getName());
				}
			}
		}
		return result;
	}

	public void merge(String owner, ABox aBox, MergePair mergePair,
			Set<WorldConstraintSystem> dependedWcs)
			throws UnsatisfiableException {
		setABox(aBox);
		setDependencySet(dependedWcs);
		Individual node = getABox().getIndividual(mergePair.getFrom());
		Individual into = getABox().getIndividual(mergePair.getInto());
		MergeUtility mergeUtility = new MergeUtility(getABox(),
				getDependencySet());
		mergeUtility.mergeConcepts(node.getName(), into.getName());
		mergeRoleAssertions(node, into);
		mergeUtility.mergeInequalities(node.getName(), into.getName());
		getABox().remove(node.getName());
		getABox().add(
				new SameIndividualAssertion(node.getName(), into.getName()));
		manageModifiedIndividuals(mergePair);
	}

	private void manageModifiedIndividuals(MergePair pair) {
		WcsData wcsData = getABox().getWorld().getWcs().getData();
		wcsData.getModifiedIndividuals().replace(
				getABox().getWorld().getName(), pair.getFrom(), pair.getInto());
	}

	private void mergeRoleAssertions(Individual toBeReplaced,
			Individual willReplace) throws UnsatisfiableException {
		MergeUtility mergeUtiliy = new MergeUtility(getABox(),
				getDependencySet());
		Iterator<Individual> i = getABox().successorIterator(toBeReplaced);
		while (i.hasNext()) {
			Individual succ = i.next();
			for (Role role : getABox().getEdges(toBeReplaced, succ)) {
				mergeUtiliy.mergeEdge(role, toBeReplaced, succ, role,
						willReplace, succ);
			}
		}
		i = getABox().predecessorIterator(toBeReplaced);
		while (i.hasNext()) {
			Individual pred = i.next();
			for (Role role : getABox().getEdges(pred, toBeReplaced)) {
				mergeUtiliy.mergeEdge(role, pred, toBeReplaced, role, pred,
						willReplace);
			}
		}
	}
}
